package SpikingNeuron;

import java.util.ArrayList;
import java.util.List;

import Generic.Genotype;
import Generic.Phenotype;
import RealGenotype.RealGenotype;

public class SpikingNeuronPhenotype implements Phenotype{

	List<Double> spikeTrain;
	
	private RealGenotype rgType;
	
	static final double MIN_A =   0.001, MAX_A =   0.02;
	static final double MIN_B =   0.01,  MAX_B =   0.3;
	static final double MIN_C = -80.0,   MAX_C = -30.0;
	static final double MIN_D =   0.1,   MAX_D =  10.0;
	static final double MIN_K =   0.01,  MAX_K =   1.0;
	
	static final double INIT_V = -60.0;
	static final double INIT_U = - 0.0;
	
	static final double SPIKE_THRESHOLD = 35;
	
	static final double TIME_CONSTANT = 10.0;
	
	static final double INPUT_CONSTANT = 10.0;
	
	public SpikingNeuronPhenotype(RealGenotype rgType,int timeSteps)
	{
		this.rgType = rgType;
		
		spikeTrain = new ArrayList<Double>();
		
		double a = rgType.get(0)*(MAX_A-MIN_A)+MIN_A;
		double b = rgType.get(1)*(MAX_B-MIN_B)+MIN_B;
		double c = rgType.get(2)*(MAX_C-MIN_C)+MIN_C;
		double d = rgType.get(3)*(MAX_D-MIN_D)+MIN_D;
		double k = rgType.get(4)*(MAX_K-MIN_K)+MIN_K;
		
		double v = INIT_V;
		double u = INIT_U;
		
		spikeTrain.add(v);
		
		for(int i = 1; i<=timeSteps; i++)
		{
			double dv = (1/TIME_CONSTANT)*(k*v*v+5*v+140-u+INPUT_CONSTANT);
			double du = (a/TIME_CONSTANT)*(b*v-u);
			
			v+=dv;
			u+=du;
			
			spikeTrain.add(v);
			
			if(v>SPIKE_THRESHOLD)
			{
				v=c;
				u+=d;
			}
		}
	}

	public Number get(int i) {
		return spikeTrain.get(i);
	}

	public List<Double> getSpikeTrain() {
		return spikeTrain;
	}

	public Genotype getGenotype() {
		return rgType;
	}

	public String getParameterString() {
		String ret = "";
		ret+="a: "+((int)((rgType.get(0)*(MAX_A-MIN_A)+MIN_A)*1000))/1000.0+", ";
		ret+="b: "+((int)((rgType.get(1)*(MAX_B-MIN_B)+MIN_B)*100))/100.0+", ";
		ret+="c: "+((int)((rgType.get(2)*(MAX_C-MIN_C)+MIN_C)*10))/10.0+", ";
		ret+="d: "+((int)((rgType.get(3)*(MAX_D-MIN_D)+MIN_D)*100))/100.0+", ";
		ret+="k: "+((int)((rgType.get(4)*(MAX_K-MIN_K)+MIN_K)*100))/100.0;
		return ret;
	}
	
}
